#!/usr/bin/env python

# Based on an example for retrieving SMS data as posted in:
#
#   http://code.google.com/p/pygooglevoice/issues/detail?id=22#c13

from googlevoice import Voice
import re
import sys
import json
import time
import os
import os.path

import BeautifulSoup

from time import mktime,strptime,strftime,localtime
from datetime import datetime,timedelta

base = "./mirror/"

vxmFeeds = ['voicemail']
smsFeeds = ['sms']
mp3Feeds = ['recorded', 'voicemail']

def extractMessages(json):
    for message in iter(json['messages']):
        yield json['messages'][message]
    return

def extractDuration(json, html):
    tree = BeautifulSoup.BeautifulSoup(html)
    htmlMessages = tree.findAll('div', attrs={'id' : True}, recursive=False)
    jsonMessages = json['messages']
    for message in htmlMessages:
        messageID = message['id']
        messageMap = jsonMessages[messageID]
        search = message.find('div', attrs={'class' : 'gc-message-players'})
        if search:
            duration = ' '.join(search.findAll(text=True))
            if duration:
                print messageID+" duration1: '"+duration.strip()+"'"
            continue
        search = message.find('div', attrs={'class' : 'gc-message-time-row'})
        if search:
            search = search.find('span', attrs={'class' : 'gc-message-call-details'})
            if search:
                duration = ' '.join(search.findAll(text=True))
                if duration:
                    print messageID+" duration2: '"+duration.strip()+"'"
            continue

def extractVoicemail(json, html):
    tree = BeautifulSoup.BeautifulSoup(html)
    transcriptBlock = tree.findAll('div', attrs={'id' : True}, recursive=False)
    jsonMessages = json['messages']
    for transcript in transcriptBlock:
        transId = transcript['id']
        transmap = jsonMessages[transId]
        transcriptDisplay = transcript.findAll(attrs={'class' : 'gc-message-message-display'})
        transcriptResult = ''
        for transcriptText in transcriptDisplay:
            transcriptResult += ' '.join([string for string in transcriptText.findAll(text=True) if string != '\n'])
        transmap['transcript'] = transcriptResult
        yield transmap
    return

def extractConversations(json, html) :
    tree = BeautifulSoup.BeautifulSoup(html)
    convBlock = tree.findAll('div', attrs={'id' : True}, recursive=False)
    jsonMessages = json['messages']
    for conv in convBlock :
        convId = conv['id']
        convmap = jsonMessages[convId]
        rows = conv.findAll(attrs={'class' : 'gc-message-sms-row'})
        messages = []
        for row in rows:
            spans = row.findAll('span', attrs={'class' : True}, recursive=False)
            msgitem = {}
            for span in spans:
                cl = span['class'].replace('gc-message-sms-', '')
                msgitem[cl] = (' '.join(span.findAll(text=True))).strip()
            messages.append(msgitem)
        convmap['messages'] = messages
        yield convmap
    return

def stripDetails(json):
    json['relativeStartTime'] = ""
    
    return json

def burstConversation(json):
    messages = []
    last = None
    for message in reversed(json['messages']):
        # use actual month day and year instead of 2000
        time = datetime.fromtimestamp(mktime(strptime(message['time']+" 2000", "%I:%M %p %Y")))
        if not last:
            last = time
        offset = last - time
        if offset.days * 86400 + offset.seconds < 0:
            last += timedelta(days=1)
            offset += timedelta(days=1)
        burstMessage = json.copy()
        del burstMessage['messages']
        messageTime = datetime.fromtimestamp(int(json['startTime'])/1000) - offset
        burstMessage['messageTime'] = int(mktime(messageTime.timetuple())*1000)
        burstMessage['displayMessageTime'] = messageTime.isoformat()
        burstMessage['sequence'] = len(json['messages'])-len(messages)
        burstMessage['id'] += "_"+str(len(json['messages'])-len(messages))
        for key in iter(message):
            burstMessage[key] = message[key]
        messages.append(burstMessage)
    return messages

def getMessages(voice, feed):
    msgs = []
    page = 0
    while True:
        page += 1
        getattr(voice,feed)(page)
        
        count = 0
        messages = []
        
        json = getattr(voice,feed).data
        html = getattr(voice,feed).html
        
        extractDuration(json, html)
        
        if feed in smsFeeds:
            messages = extractConversations(json, html)
        elif feed in vxmFeeds:
            messages = extractVoicemail(json, html)
        else:
            messages = extractMessages(json)
        for message in messages:
            count += 1
            msgs.insert(0, message)
        if count < 1:
            break
        print 'page %d' % page
    return msgs

def saveMessages(feed, messages):
    if feed in smsFeeds:
        for conversation in messages:
            for message in burstConversation(conversation):
                saveMessage(message, feed)
    else:
        for message in messages:
            saveMessage(message, feed)

def saveMessage(message, feed):
    outputDir = base+feed+'/'
    message = stripDetails(message)
    if feed in smsFeeds and 'messageTime' in message:
        name = time.strftime("%Y%m%d %H%M%S",time.localtime(int(message['messageTime'])/1000))
    else:
        name = time.strftime("%Y%m%d %H%M%S",time.localtime(int(message['startTime'])/1000))
    if message['phoneNumber'] != "":
        name += " "+message['phoneNumber']
    else:
        name += " Unknown"
    name += " "+message['id'].lower()
    print name
    ensureDirectory(outputDir)
    f = open(outputDir+name+'.txt', 'w')
    f.write(json.dumps(message,sort_keys=True, indent=4))
    f.close()
    if feed in mp3Feeds:
        voice.download(message['id'], outputDir, name+".mp3")

def ensureDirectory(path):
    if not os.path.isdir(path):
        try:
            os.makedirs(path)
        except OSError, e:
            if e.errno != errno.EEXIST:
                raise

voice = Voice()
voice.login()

for feed in ['received', 'placed', 'missed', 'sms', 'recorded', 'voicemail']:
    print feed
    messages = getMessages(voice, feed)
    print len(messages)
    saveMessages(feed, messages)
